/*
 * Copyright (c) Huawei Device Co., Ltd. 2023. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef SESSION_H
#define SESSION_H

#include <mutex>
#include "common_utils.h"
#include "isecure_element_session.h"

namespace OHOS {
namespace SE {
namespace OMAPI {
class Reader;
class SEService;
class Channel;

/**
 * @brief Instances of this class represent a connection session to one of the SEs available on the device. These
 * objects can be used to get a communication channel with an applet in the SE. This channel can be the basic channel or
 * a logical channel.
 */
class Session : public std::enable_shared_from_this<Session> {
public:
    /**
     * @brief Constructor to create the instance of Session.
     * @param service The service for all readers and all sessions.
     * @param session The session that create the channel.
     * @param reader The reader proxy for IPC with the remote service.
     */
    Session(std::weak_ptr<SEService> service, sptr<ISecureElementSession> session, std::weak_ptr<Reader> reader);

    ~Session();

    /**
     * @brief Get the reader that provides this session.
     * @param reader The reader object bound to this session.
     * @return The status code for function calling.
     */
    int GetReader(std::weak_ptr<Reader> &reader);
    /**
     * @brief Get the ATR of this SE. A Null value SHALL be returned if the ATR for this SE is not available.
     * @param atr The ATR as a byte array or Null.
     * @return The status code for function calling.
     */
    int GetATR(std::string &atr);
    /**
     * @brief Close the connection with the SE. This will close any channels opened by this application with this SE.
     * @return The status code for function calling.
     */
    int Close(void);
    /**
     * @brief Tells if this session is closed.
     * @param isClosed True if the session is closed, false otherwise.
     * @return The status code for function calling.
     */
    int IsClosed(bool &isClosed);
    /**
     * @brief Close any channels opened on this session.
     * @return The status code for function calling.
     */
    int CloseChannels(void);
    /**
     * @brief Get access to the basic channel, as defined in [ISO 7816-4] (the one that has number 0). The obtained
     * object is an instance of the channel class.
     * @param aid The AID of the applet to be selected on this channel, as a byte array, or Null if no applet is to be
     * selected.
     * @param p2 The P2 parameter of the SELECT APDU executed on this channel.
     * @param channel An instance of channel if available or Null.
     * @param apduResp The APDU response received.
     * @return The status code for function calling.
     */
    int OpenBasicChannel(const std::string &aid, int p2, std::shared_ptr<Channel>& channel, std::string &apduResp);
    /**
     * @brief This method is provided to ease the development of mobile applications and for backward compatibility with
     * existing applications. This method is equivalent to openBasicChannel(aid, P2=0x00).
     * @param aid The AID of the applet to be selected on this channel, as a byte array, or Null if no applet is to be
     * selected.
     * @param channel An instance of channel if available or Null.
     * @param apduResp The APDU response received.
     * @return The status code for function calling.
     */
    int OpenBasicChannel(const std::string &aid, std::shared_ptr<Channel>& channel, std::string &apduResp);
    /**
     * @brief Open a logical channel with the SE, selecting the applet represented by the given AID (when the AID is not
     * Null and the length of the AID is not 0).
     * @param aid The AID of the applet to be selected on this channel, as a byte array.
     * @param p2 The P2 parameter of the SELECT APDU executed on this channel.
     * @param channel An instance of channel. Null if the SE is unable to provide a new logical channel or is unable to
     * retrieve Access Control rules due to the lack of an available logical channel.
     * @param apduResp The APDU response received.
     * @return The status code for function calling.
     */
    int OpenLogicalChannel(const std::string &aid, int p2, std::shared_ptr<Channel>& channel, std::string &apduResp);
    /**
     * @brief This method is provided to ease the development of mobile applications and for backward compatibility with
     * existing applications. This method is equivalent to openLogicalChannel(aid, P2=0x00)
     * @param aid The AID of the applet to be selected on this channel, as a byte array.
     * @param channel An instance of channel. Null if the SE is unable to provide a new logical channel or is unable to
     * retrieve Access Control rules due to the lack of an available logical channel.
     * @param apduResp The APDU response received.
     * @return The status code for function calling.
     */
    int OpenLogicalChannel(const std::string &aid, std::shared_ptr<Channel>& channel, std::string &apduResp);

private:
    // check the service and session status.
    int InnerCheckSessionStatus(void);

    // used to IPC with the remote session of service.
    sptr<ISecureElementSession> sessionIface_{};

    // used to save the bound service instance.
    std::weak_ptr<SEService> boundService_{};

    // used to save the bound reader instance.
    std::weak_ptr<Reader> boundReader_{};

    // mutex for IPC calling to remote service
    std::mutex mutex_{};
};
}  // namespace OMAPI
}  // namespace SE
}  // namespace OHOS
#endif // SESSION_H
